package org.si.icon;

import java.awt.Component;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Insets;
import javax.swing.border.Border;

/**
 * Wraps a {@link ScalableIcon} in a {@link Border}. The default size of the icon is the size of the inner ScalableIcon
 * with the border insets added onto it.
 *
 * <p><b>Implementation Note</b>: The component used to get the insets of the border when calling {@link
 * #getIconWidth()} and {@link #getIconHeight()} is an annonomous inner class of the type {@code new Component() {}}.
 * Please don't make any assumptions that just because you are painting onto another type that that instance will be
 * given in the {@link Border#getBorderInsets(Component)} method.
 *
 * @author Matt Nathan
 * @see IconWrapper
 */
public class BorderIcon extends AbstractScalableIcon {

    /** Used for giving to the Border when we need the insets and we don't have access to another component. */
    private static final Component INSETS_COMPONENT = new Component() {
    };

    private final ScalableIcon inner;
    private final Border border;





    /**
     * Wrap the inner ScalableIcon in a Border.
     *
     * @param inner  The icon to wrap
     * @param border The border to wrap it with.
     */
    public BorderIcon(ScalableIcon inner, Border border) {
        this.inner = inner;
        this.border = border;
    }





    /**
     * Makes sure that the inner icon is scaled acording to it's own fitInto method such that there is enough room for
     * the border to fit around the edge.
     *
     * @param c      The component that this will be painted to.
     * @param width  The target width for the icon paint area.
     * @param height The target height for the icon paint area.
     * @param result The place to put the size the icon is hapy painting in.
     */
    @Override
    public void fitInto(Component c, int width, int height, Dimension result) {
        Insets borderInsets = border.getBorderInsets(c);
        width -= borderInsets.left + borderInsets.right;
        height -= borderInsets.top + borderInsets.bottom;
        if (inner instanceof AbstractScalableIcon) {
            AbstractScalableIcon icon = (AbstractScalableIcon) inner;
            icon.fitInto(c, width, height, result);
        } else {
            result.setSize(inner.fitInto(c, width, height));
        }
        result.width += borderInsets.left + borderInsets.right;
        result.height += borderInsets.top + borderInsets.bottom;
    }





    @Override
    public void paintIcon(Component c, Graphics g, int x, int y, int width, int height) {
        Insets i = border.getBorderInsets(c);
        inner.paintIcon(c, g, x + i.left, y + i.top, width - i.left - i.right, height - i.top - i.bottom);
        border.paintBorder(c, g, x, y, width, height);
    }





    @Override
    public int getIconWidth() {
        Insets i = border.getBorderInsets(INSETS_COMPONENT);
        return inner.getIconWidth() + i.left + i.right;
    }





    @Override
    public int getIconHeight() {
        Insets i = border.getBorderInsets(INSETS_COMPONENT);
        return inner.getIconHeight() + i.top + i.bottom;
    }





    /**
     * Get the icon that is being wrapped.
     *
     * @return The inner icon.
     */
    public ScalableIcon getInner() {
        return inner;
    }





    /**
     * Get the border that is wrapping the inner icon.
     *
     * @return The border.
     */
    public Border getBorder() {
        return border;
    }
}
